﻿/************************************************************************
 * SMLib - State Model Library
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     SMLib\Automata\DFA\SUL_DFA_Emulator.cs
 * Description  :     Implementation of a SUL in which the underlying model is a given DFA
 * Change log   :     -1 March 2013:  Initial version
 * To Do        :     
 ************************************************************************/
using System;
using System.Collections.Generic;
using SMLib.Automata.Base;

namespace SMLib.Automata.DFA
{
    /// <summary>
    /// Emulator of a DFA
    /// <remarks>It works in two modes: Active mode where you can execute the underlying DFA step by step
    /// and check the acceptability of current word in each step (it is a kind of machine view), Passive mode where you can only check
    /// acceptability of a word to the language (it is a sort of language view) </remarks>
    /// </summary>
    public class SUL_Emulator_DFA : IBlackBox_RegLanguage
    {
        DFA.DFA_State currentNode;
        DFA machine;
        bool isActive;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="machine">the underlaying of SUL</param>
        /// <param name="isActive">If true, the system is active. If not, it is passive. The functions you can use in 
        /// active mode are different than the ones in passive mode
        /// </param>
        public SUL_Emulator_DFA(DFA machine, bool isActive)
        {
            this.machine = machine;
            this.isActive = isActive;
            Reset();
        }

        #region IBlackBox_DFA_Active Members (Active Mode)

        /// <summary>
        /// Reset the DFA to initial state
        /// <remarks>It works in active mode</remarks>
        /// </summary>
        public void Reset()
        {
            if (!isActive)
                throw new Exception("This function cannot be called in passive mode of DFA!");

            currentNode = (DFA.DFA_State)machine.InitialState;
        }

        /// <summary>
        /// Go one step the SUL ahead
        /// <remarks>It works in active mode</remarks>
        /// </summary>
        /// <param name="input">the input of step</param>
        public void Step(ISymbol input)
        {
            if (!isActive)
                throw new Exception("This function cannot be called in passive mode of DFA!");

          		bool found=false;
                foreach (DFA.DFA_Transition t in currentNode.Transitions)
                {
                    if (t.Label.Equals(input))
                    {
                        currentNode = (DFA.DFA_State)t.Destination;
						found=true;
						break;
                    }
                }
				if(!found)
					throw new Exception("Transition not found in the alphabet!");
			
        }

        /// <summary>
        /// Check whether the current state is accepting or not
        /// <remarks>It works in active mode</remarks>
        /// </summary>
        /// <returns>true if accepting, false in other case</returns>
        public bool isAccepting()
        {
            if (!isActive)
                throw new Exception("This function cannot be called in passive mode of DFA!");

            return currentNode.isAccepting;
        }

        public bool isAccepting(List<ISymbol> w)
        {
            if (!isActive)
                throw new Exception("This function cannot be called in passive mode of DFA!");

            return currentNode.isAccepting;
        }

        public Alphabet InputAlphabet
        {
            get
            {
                return this.machine.InputAlphabet;
            }
        }
        #endregion

        #region IBlackBox_RegLanguage Members

        /// <summary>
        /// Check whether a word is accepting by a black box DFA or not
        /// <remarks>It works in passive mode</remarks>
        /// </summary>
        /// <param name="input">the input word to be checked against DFA</param>
        /// <returns>true if it is accepting, false in other case</returns>
        public bool isAccepting(Automata.Base.Word input)
        {
			/*
			if (isActive)
                throw new Exception("This function cannot be called in Active mode of DFA!");
			*/
			Reset();
			
            for (int i = 0; i < input.Length; i++)
            {
                ISymbol symb = input[i];
				bool found=false;
                foreach (DFA.DFA_Transition t in currentNode.Transitions)
                {
                    if (t.Label.Equals(symb))
                    {
                        currentNode = (DFA.DFA_State)t.Destination;
						found=true;
						break;
                    }
                }
				if(!found)
					throw new Exception("Transition not found in the alphabet!");
            }
            return currentNode.isAccepting;
        }

        #endregion
    }
}
